#include "stdafx.h"
#include "qxmlparser.h"


using namespace micro::qxml;






bool  QXMLParser::isWhite(TCHAR a)
{
	//_istspace(a);

	return (a ==_T(' ') || a ==_T('\t') || a==_T('\n') || a==_T('\r') || a == 0xfeff ) ;

}


void  QXMLParser::SkipWhite(Buffer * buf)
{
	while( isWhite( buf->date[buf->pos] ) )
		buf->pos++;

}

bool  QXMLParser::Expect(Buffer * buf, TCHAR a)
{ 
	if( buf->date[buf->pos] == a )
	{	
		buf->pos++;
		return true;
	}

	//fwprintf(stderr, _T("Eroare: %c expected! but have %c"),a, buf->date[buf->pos] );
	return false;
}
TCHAR  QXMLParser::Next(Buffer * buf)
{

	if(buf->pos < buf->len )
		return buf->date[buf->pos];

	return 0;

}
void QXMLParser::Add(QxmlNode * root, QxmlNode* fiu)
{
	
		
	if(root->children.tail)
		root->children.tail->next = fiu;
	
	
	root->children.tail = fiu;
	
	if(root->children.head == nullptr)
		root->children.head = fiu;

	root->children.contor++;

}

QxmlNode * QXMLParser::GetRoot(Buffer *buf)
{
	QxmlNode *root = nullptr;
	QxmlNode *fiu = nullptr;
	
	QString sir;

	Expect(buf, _T('<') );	 

	while( !isWhite( Next(buf) ) &&  Next(buf) != _T('/')  &&  Next(buf) != _T('>')  )
	{
		sir  += buf->date[ buf->pos++ ];		  
	}
 
	root = new QxmlNode(); 
	root->nume = sir;
	root->tip = QTAG;
	
	SkipWhite(buf);

	if(Next(buf) == _T('/'))
	{
		Expect(buf, _T('/') );
		SkipWhite(buf);
		Expect(buf, _T('>') );
		return root;
	}

	SkipWhite(buf);
	while( Next(buf) !=  _T('>') && Next(buf) !=  _T('/'))
	{	 
		sir.Empty();
		while( Next(buf) != _T('=') &&  Next(buf) != _T(' ') ) //pana la egal sau space
			sir += buf->date[buf->pos++];
						
		fiu = new QxmlNode(); 
		fiu->nume =  sir ;
		fiu->tip =  QATTR ;

		SkipWhite(buf);//eventual
		Expect(buf, _T('='));
		SkipWhite(buf);//eventual
		Expect(buf, _T('\''));

 		sir.Empty();
		while( Next(buf) != _T('\'') )
			sir  += buf->date[buf->pos++];
		 
		fiu->valoare =  sir ;
		Expect(buf,  _T('\'')  );
		Add(root, fiu);

		SkipWhite(buf);
	}

	if(Next(buf) == _T('/') )
	{
		Expect(buf, _T('/'));
		SkipWhite(buf);
		Expect(buf,  _T('>') );
		return root;
	}
	 
	Expect(buf,  _T('>') );
	SkipWhite(buf);

	bool stop = false;  
	while( !stop && buf->pos < buf->len)
	{
		SkipWhite(buf);

		if(Next(buf) != _T('<') )
		{
			
			sir.Empty();
			while(Next(buf) != _T('<') )
				sir += buf->date[buf->pos++];

			fiu = new QxmlNode();
			fiu->valoare = sir.Trim();
			fiu->nume =  _T("Text") ;
			fiu->tip =  QTEXT  ;

			Add(root, fiu);
		}
		else
			//desi este egal cu '<'
			if( buf->date[buf->pos+1] == _T('/') )
			{
				Expect(buf, _T('<') );
				Expect(buf, _T('/') );

				sir.Empty();
				while( Next(buf) != _T('>') )
					sir += buf->date[buf->pos++];
			 
				if ( root->nume !=  sir   )
				{
					//fwprintf(stderr, "invalid terminator- expected :%s", root->nume);		 
					return nullptr;
				}; 
				//consum inchizatorul
				
				Expect(buf,  _T('>')  );
				stop = true;
			}
			else
			{
				fiu = GetRoot( buf);
				Add(root,fiu);
			}
	}
	return root; 
}


bool QXMLParser::ParseInput(TCHAR *buff, int len)
{	 
	
	Buffer  buf;

	buf.date	= buff;
	buf.len		= len;
	buf.pos		= 0;
	
	SkipWhite(&buf);  

	if(Next(&buf)==_T('<'))
	   m_root =  GetRoot(&buf);


	return m_root!=nullptr;
	
}


QxmlNode * QXMLParser::FindTag(const QString & str, QxmlNode * root  )
{
	if(nullptr == root)
		return nullptr;

	if(root->nume == str && root->tip == QTAG)
		return root;

	if(root->children.contor>0)
	{
		QxmlNode * p = root->children.head;
		while(p)
		{
			QxmlNode * res = FindTag(str, p);

			if (res) return res;
			p = p->next;
		}
	}
	
	return nullptr;

}
bool QXMLParser::GetList(const QString & str, QStringArray & list)
{
	list.RemoveAll();

	QxmlNode * node = FindTag(str, m_root);

	if(!node)
		return false;



	QxmlNode *  p = node->children.head;
	while(p)
	{
		if(p->tip != QATTR )
		{
			QxmlNode *  q = p->children.head;
			if(q)
				list.Add( q->valoare);
		}
		p = p->next;
	}
	 

	return true;
	
}


long  QXMLParser::GetLongAttr(const QString & tag, const QString & attr, long def  )
{
	QxmlNode * node = FindTag(tag, m_root);

	if(!node)
		return def;



	QxmlNode *  p = node->children.head;
	while(p)
	{
		if(p->tip == QATTR && p->nume == attr )
		{
			 
				return  _ttol ( p->valoare);
		}
		p = p->next;
	}
	 

	return def;

}

QxmlNode *	QXMLParser::GetTagNode(const QString & tag)
{
		QxmlNode * node = FindTag(tag, m_root);
		return node;


}
QString	QXMLParser::GetStrAttr(QxmlNode *node, const QString & attr)
{
	ASSERT(node);

	QxmlNode *  p = node->children.head;
	while(p)
	{
		if(p->tip == QATTR && p->nume == attr )
		{
			 
				return    p->valoare;
		}
		p = p->next;
	}
	
	return QString();


}
long	QXMLParser::GetLongAttr(QxmlNode *node , const QString & attr)
{
	ASSERT(node);
	 
	return  _ttol ( GetStrAttr(node, attr) );
}


QxmlNode *	QXMLParser::GetFirstTag(QxmlNode *node, const QString & tag)
{
	ASSERT(node);

	QxmlNode *  p = node->children.head;
	while(p)
	{
		if(p->tip == QTAG && p->nume == tag )
		{
			 
				return    p;
		}
		p = p->next;
	}
	
	return nullptr;


}

QxmlNode *	QXMLParser::GetNextTag(QxmlNode *node, const QString & tag)
{
	ASSERT(node);

	QxmlNode *  p = node->next;
	while(p)
	{
		if(p->tip == QTAG && p->nume == tag )
		{
			 
				return    p;
		}
		p = p->next;
	}
	
	return nullptr;


}